package com.smart.common.exception;


import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import com.smart.common.entities.ajax.AjaxResult;
import com.smart.common.entities.ajax.AjaxResultEnum;
import lombok.extern.log4j.Log4j2;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;


/**
 * @author Administrator
 */
@ControllerAdvice
@ResponseBody
@Log4j2
public class SmartExceptionHandler {


    /**
     * 捕获Arm系统异常
     */
    @ExceptionHandler(SmartException.class)
    public AjaxResult<?> exceptionHandler(RuntimeException e) {
        String message = e.getMessage();
        return AjaxResult.fail(AjaxResultEnum.FAILURE.getCode(), message);
    }


    /**
     * 全局异常拦截（拦截项目中的NotLoginException异常）
     */

    @ExceptionHandler(NotLoginException.class)
    public AjaxResult<?> exceptionHandler(NotLoginException e) {
        switch (e.getType()) {
            case NotLoginException.INVALID_TOKEN:
                return AjaxResult.fail(AjaxResultEnum.TOKEN_INVALID_TOKEN);
            case NotLoginException.TOKEN_TIMEOUT:
                return AjaxResult.fail(AjaxResultEnum.TOKEN_TIMEOUT);
            case NotLoginException.BE_REPLACED:
                return AjaxResult.fail(AjaxResultEnum.TOKEN_BE_REPLACED);
            case NotLoginException.KICK_OUT:
                return AjaxResult.fail(AjaxResultEnum.TOKEN_KICK_OUT);
            case NotLoginException.TOKEN_FREEZE:
                return AjaxResult.fail(AjaxResultEnum.TOKEN_FREEZE);
            default:

                return AjaxResult.fail(5000, e.getMessage());

        }


    }


    /**
     * 全局异常拦截（拦截项目中的NotLoginException异常）
     */

    @ExceptionHandler(NotPermissionException.class)
    public AjaxResult<?> exceptionHandler(NotPermissionException e) {
        return AjaxResult.fail(AjaxResultEnum.ACCOUNT_ACCESS_ERROR);

    }


    /**
     * 字段验证主键
     */

    @ExceptionHandler(BindException.class)
    public AjaxResult<?> exceptionHandler(BindException e) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        if (fieldError == null) {
            return AjaxResult.fail(AjaxResultEnum.REQUEST_PARAMS_ERROR.getCode(), "字段验证:未知异常");
        }
        BindingResult bindingResult = e.getBindingResult();
        String field = bindingResult.getFieldError().getField();
        String defaultMessage = fieldError.getDefaultMessage();

        String enumErr = "no enum constant";
        if (defaultMessage.toLowerCase().contains(enumErr)) {
            return AjaxResult.fail(AjaxResultEnum.REQUEST_PARAMS_ERROR.getCode(), field + "字段:传递值不是合法的枚举属性");
        }

        return AjaxResult.fail(AjaxResultEnum.REQUEST_PARAMS_ERROR.getCode(), fieldError.getDefaultMessage());
    }


    /**
     * 数据类型异常处理
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public AjaxResult<?> exceptionHandler(HttpMessageNotReadableException e) {

        return AjaxResult.fail(AjaxResultEnum.REQUEST_PARAMS_ERROR.getCode(), "请求数据中格式错误或存在错误的数据类型！" + e.getMessage());
    }


    /**
     * 校验list参数 使用@Validated 和 @Valid配合使用 该拦截器处理@Vaild异常
     * 我们注解中的message可以从violation中取出
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public AjaxResult<?> exceptionHandler(ConstraintViolationException e) {

        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            return AjaxResult.fail(AjaxResultEnum.valueOf(violation.getMessage()));
        }
        return AjaxResult.fail(AjaxResultEnum.REQUEST_PARAMS_ERROR.getCode(), "字段验证:未知异常");
    }


    /**
     * 校验数据类型是否正常
     * 我们注解中的message可以从violation中取出
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public AjaxResult<?> exceptionHandler(MethodArgumentTypeMismatchException e) {
        return AjaxResult.fail(AjaxResultEnum.REQUEST_PARAMS_ERROR.getCode(), "请求参数包含非法的数据类型" + e.getMessage());
    }


    /**
     * 断言工具注解
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public AjaxResult<?> exceptionHandler(IllegalArgumentException e) {
        return AjaxResult.fail(AjaxResultEnum.FAILURE.getCode(), e.getMessage());
    }

    /**
     * 断言工具注解
     */
    @ExceptionHandler(IllegalStateException.class)
    public AjaxResult<?> exceptionHandler(IllegalStateException e) {
        return AjaxResult.fail(AjaxResultEnum.FAILURE.getCode(), e.getMessage());
    }


    @ExceptionHandler(ConversionFailedException.class)
    public AjaxResult<?> exceptionHandler(ConversionFailedException e) {
        return AjaxResult.fail(AjaxResultEnum.FAILURE.getCode(), e.getMessage());
    }


}


